#include "soc_uart.h"
#include "main.h"


#ifdef HAL_UART_MODULE_ENABLED

SOC_Uart::SOC_Uart(UartDevId id, void *handle)
{
    InitPeripheral(id, this, handle);
}

SOC_Uart::~SOC_Uart()
{
}

void SOC_Uart::WriteByte(uint8_t value)
{
    Write((uint8_t*)&value, 1);
}

void SOC_Uart::Write(const uint8_t *buf, int len)
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);
    //由于串口的__HAL_LOCK()机制，可能不成功，这里发送和接收共用lock，
    while(HAL_UART_Transmit(h, (uint8_t*)buf, len, HAL_MAX_DELAY) == HAL_BUSY);
}

void SOC_Uart::Write(const char *str)
{
    int len = strlen(str);
    //一次写入，效率高
    Write((const uint8_t*)str, len);
}

void SOC_Uart::Write(const std::string &str)
{
    if(str.size() == 0)
        return;
        
    Write((const uint8_t *)str.c_str(), str.size());
}

void SOC_Uart::WriteLine(const char *str)
{
    Write(str);
    Write((const char *)NEWLINE);
}

void SOC_Uart::WriteLine(const std::string &str)
{
    WriteLine(str.c_str());
}

void SOC_Uart::WriteDMA(const uint8_t *buf, int len)
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);

    if(h->hdmatx == nullptr)
        return;
    while(HAL_DMA_GetState(h->hdmatx) != HAL_DMA_STATE_READY);
    while(h->gState != HAL_UART_STATE_READY);  //DMA先完成，然后UART发送中断才完成，所以判断一下，否则HAL_UART_Transmit_DMA发送不成功
    HAL_UART_Transmit_DMA(h, buf, len);
}

bool SOC_Uart::IsDMAIdle()
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);

    if(h->hdmatx == nullptr)
        return false;
    
    return HAL_DMA_GetState(h->hdmatx) == HAL_DMA_STATE_READY;
}

int SOC_Uart::ReadByte()
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);
    int c = -1;
    HAL_UART_Receive(h, (uint8_t*)&c, 1, HAL_MAX_DELAY);
    return c;
}

void SOC_Uart::StartReceive_IT()
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);

    //由于串口的__HAL_LOCK()机制，可能启动不成功，这里发送和接收共用lock，
    //实际上应该是HAL库的BUG，串口本来是全双工， 所以压力测试下，同时收发，可能会出错
    //这里多次尝试即可
    
    //1、判断是否在接收状态
    if(h->RxState == HAL_UART_STATE_BUSY_RX) 
        return;
    //2、开启, 如果返回HAL_BUSY，一定是Lock机制导致
    // while(HAL_UART_Receive_IT(h, (uint8_t*)&m_recvBuffer, 1) == HAL_BUSY);
    //中断中不能采用while，可能导致发送lock后，被中断抢占，然后永远无法unlock，所以这里强制设置一下
    __HAL_UNLOCK(h);
    HAL_UART_Receive_IT(h, (uint8_t*)&m_recvBuffer, 1);
}

void SOC_Uart::StartReceive_DMA()
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);
    if(h->hdmarx == nullptr)
        return;

    m_currentDMABufferIndex = (m_currentDMABufferIndex + 1) % 2;
    auto ptr = m_currentDMABufferIndex == 0? m_recvBuffer_DMA1 : m_recvBuffer_DMA2;
    HAL_UARTEx_ReceiveToIdle_DMA(h, ptr, SOC_UART_DMA_RECV_BUFFER_SIZE);
    h->hdmarx->XferHalfCpltCallback = nullptr; //[不需要half中断] HAL_UARTEx_ReceiveToIdle_DMA 函数设置了XferHalfCpltCallback
}

void SOC_Uart::SetDataReceivedCallBack(const IF_SOC_Uart::DATA_RECEIVED_CB &func)
{
    m_dataRecvCb = func;
}

void SOC_Uart::SetDataReceivedCallBack_DMA(const IF_SOC_Uart::DATA_RECEIVED_CB_DMA &func)
{
    m_dataRecvCb_DMA = func;
}

void SOC_Uart::RaiseDataReceivedCallBack()
{
    //先开启下次 
    StartReceive_IT();
    //在通知
    if(m_dataRecvCb)
    {
        m_dataRecvCb(*this, m_recvBuffer);
    }
}

void SOC_Uart::RaiseIdleEventCallBack()
{
    auto h = GetHandleAs<UART_HandleTypeDef>(m_devId);
    if(h->hdmarx == nullptr)
        return;

    int len = SOC_UART_DMA_RECV_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(h->hdmarx);
    auto ptr = m_currentDMABufferIndex == 0? m_recvBuffer_DMA1 : m_recvBuffer_DMA2;
    
    //先开启下次DMA
    StartReceive_DMA();

    //然后在通知处理数据
    if(m_dataRecvCb_DMA)
    {
        m_dataRecvCb_DMA(*this, ptr, len);
    }

    //也要通知字节接收
    if(m_dataRecvCb)
    {
        for(int i = 0; i < len; i++)
        {
            m_dataRecvCb(*this, ptr[i]);
        }
    }
}

#endif 
